struct DummyWorld
{
	float4x4 World[2];
};

struct DummyInfo
{
	//int Id; // Index != Id
	int ParentIndex; // Points to the parent node
	//int ParentsCount; // Indicates how many nodes influence this one
};

StructuredBuffer<DummyInfo> g_DummiesHierarchy : register (t0);
StructuredBuffer<DummyWorld> g_DummiesLclWorlds : register (t1);
RWStructuredBuffer<DummyWorld> g_DummiesGlbWorlds : register (u0);

#define _Max_parents_count_ 64 // The limit to get rid of in the nearest future.

groupshared DummyWorld gs_DummiesWorldsCache[_Max_parents_count_]; 

[numthreads(2, 1, 1)] void main( 
	in const uint3 groupId : SV_GroupID,
	in const uint3 groupThreadId : SV_GroupThreadID
	)
{
	const int dummyIndex = groupId.x;
	const int worldIndex = groupThreadId.x;

	const bool isActiveThread = worldIndex == 0;
	volatile int parentIndex = g_DummiesHierarchy[dummyIndex].ParentIndex;
	
	//
	// DEBUG >>>
	if (isActiveThread)
	{
		printf("----------------------------------------------------");
		printf("DummyIndex = %d ParentIndex = %d", dummyIndex, parentIndex);
		printf("----------------------------------------------------");
	}
	// DEBUG <<<
	//


	if (parentIndex == -1)
	{
		//
		// DEBUG >>>
		if (isActiveThread) printf("=> Skeleton root.");
		// DEBUG <<<
		//

		g_DummiesGlbWorlds[dummyIndex].World[worldIndex] = g_DummiesLclWorlds[dummyIndex].World[worldIndex];
	}
	else
	{
		volatile int cacheIndex = 0;
		[loop] while (parentIndex != (-1))
		{
			gs_DummiesWorldsCache[cacheIndex].World[worldIndex] = g_DummiesLclWorlds[parentIndex].World[worldIndex];

			//
			// DEBUG >>>
			if (isActiveThread) printf("=> Then %d", parentIndex);
			// DEBUG <<<
			//

			parentIndex = g_DummiesHierarchy[parentIndex].ParentIndex;
			cacheIndex++;
		}

		//
		// DEBUG >>>
		if (isActiveThread) printf("=> Bone is influenced by %d parent bones.", cacheIndex);
		// DEBUG <<<
		//

		volatile float4x4 glbWorld = gs_DummiesWorldsCache[0].World[worldIndex];
		[loop] for (parentIndex = 1; parentIndex <= cacheIndex; parentIndex++)
		{
			glbWorld = mul(glbWorld, gs_DummiesWorldsCache[parentIndex].World[worldIndex]);
		}

		g_DummiesGlbWorlds[dummyIndex].World[worldIndex] = mul(g_DummiesLclWorlds[dummyIndex].World[worldIndex], glbWorld);
	}
}